#pragma once
#include "renderbase.h"

class SilhouetteRender :
	public RenderBase
{
public:
	SilhouetteRender(void);
	~SilhouetteRender(void);

public:
	//Silhouette Rendering
	void Render(ABSurface* pABS,const D3DXMATRIX* pmView, const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt, const D3DXVECTOR3* pLookAtPt, const D3DXVECTOR3 pLightDir[], const D3DXCOLOR pLightColor[], int nLight, const RECT* renderSize, int surfWidth, int surfHight);
	void Render(ABSurface* pABS,const D3DXMATRIX* pmView, const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt, const D3DXVECTOR3* pLookAtPt, const D3DXVECTOR3 pLightDir[], const D3DXCOLOR pLightColor[], int nLight, int width, int hight);

	void SilhouetteRendering();
	void SilMainLoop();
	void SilInitParam();

	void FitPlane(double p1[], double p2[], double p3[], double plane[]);
	void GetScanPlaneUVW(int scanline, double scanplane[], double boxX[], double boxY[], double boxZ[]);
	void GetPolarUVW(double func[][4][4], double polar[][4][4], double boxX[], double boxY[], double boxZ[], int dx, int dy, int dz);
	void ChangeUVW(double uvw[], double boxX[], double boxY[], double boxZ[]);
	void ReParametrization(double func[][4][4], double polar[][4][4], int dx, int dy, int dz);
	void ReParametrizationPlane(double scanPlane[], double plane[][2][2]);

	void SilCriticalPoint(const int scanline, double func[][4][4], double polar[][4][4], double plane[][2][2], double scanPlane[], double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], int dx, int dy, int dz, double* intersection_UVW, int* sil_n);
	void SetA(double A[][4], int deg);
	void GetBinom(int Bin[], int deg);
	void BezoutRes_plane(double re[][7], double H[][4][4], double L[][2][2], int dx, int dy, int dz);
	void GetProduct(double product[][7], double a[][4], double t0[][2], double t1[][2], int rind, int dr, int ds, int dt);
	void star(double re[][7], double A[][7], double B[][2], int ma, int na, int mb, int nb);
	void starProduct(double re[], double A1[], double B1[], double A2[], double B2[], int n);
	void BezoutRes(double re[][6][13], double H1[][7], double H2[][7], int n1, int n2);
	
	void CheckMultiplicity(int n, bool bNonSymEig, double* A, double* B, int* Multi, double* err_bound, double* wr, double* wi, double* rconde, double* rcondv);
	void ClusterEigen(int n, double* Magnitude, int* sortM, double* A, double* B, bool bNonSymEig, int* Multi, double* err_bound, double* wr, double* wi, double* rconde, double* rcondv);
	bool GetCondNum(int n, double* M, double* rcond);
	void ClusterCondNum(double* err);
	void GetFrobeniusNormal(int n, double* M, double* norm);

	void GetCriticalPointUVW(const long int n, int* index, int* Multi, double* err, int could_be, double* wr, double* wi, double* vl, const long int ldvl, double* vr, const long int ldvr, double* rconde, double* rcondv, const int scanline, double* scanPlane, double func[][4][4], double polar[][4][4], double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], int dx, int dy, int dz, double FS[][7], int sn, double* intersection_UVW, int* sil_n);
	void solve_s(double* s_sn, int* rootn, double* scond, double t, int n, int ind, double* vr, double* vl, double conde, double condv, double FS[][7], int sn, int tn, double err_bound, int Multi);
	void solve_s_2(double* s_sn, int* rootn, double* scond, double t, int n, double FS[][7], int sn, int tn, double cond, int Multi);
	void GetPolynomial(double* poly, double func[][4][4], int degx, int degy, int degz, double y, double z);
	void solvePolynomial(double* root, double* poly, int deg, int* rootn, double* rconde);

	void SilCriticalPointUVWTrace(double point[], double func[][4][4], double polar[][4][4], double scanPlane[], double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], int dx, int dy, int dz, int* sil_n);
	void RefineUVW(const double point[], double func[][4][4], double polar[][4][4], double scanPlane[], double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], int dx, int dy, int dz, double conde, double err_bound, double* intersection_UVW, int* sil_n);
	void GetJacobi(double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], double func[][4][4], double polar[][4][4], int dx, int dy, int dz);
	void usrfun(double point[], double fValue[], double jacobi[][3], double func[][4][4], double polar[][4][4], double scanPlane[], double jacobi_f[][4][4][4], double jacobi_p[][4][4][4], int dx, int dy, int dz);
	void EvalBezier(double u, double v, double w, int nx, int ny, int nz, double f[][4][4], double* re);
	void GetDeltaPoint(double fValue[], double jacobi[][3]);
	void GaussElimination(double A[][3], double b[], int n);

	void SilCriticalPointUVW2Scan(int* Scanline_X, double* Scanline_Z, double* intersect, int* sil_n, int scanline, double* boxX, double* boxY, double* boxZ);
	//void SilCriticalPointUVW2ScanTrace(int* Scanline_X, double* Scanline_Z, double* intersect, int* sil_n, double* boxX, double* boxY, double* boxZ);
	void SilCriticalPointOutput(int* Scanline_X, double* Scanline_Z, double* inter_UVW, int* sil_n, int line);
	void SilCriticalPointOutputTrace(int* Scanline_X, double* Scanline_Z, const int sil_n, int line);

	void LaunchInterval(int* Scanline_X, double* Scanline_Z, double* inter_UVW, double eye[], const int sil_n, int line, double func[][4][4], double scanplane[], double jacobi_f[][4][4][4], int dx, int dy, int dz, double boxX[], double boxY[], double boxZ[]);
	void GetVerticalPlaneUVW(int vertline, double vertplane[], double boxX[], double boxY[], double boxZ[]);
	void SilCriticalPointUVWTraceInterval(double point[], bool* bOutDomain, double eye[], double func[][4][4], double scanplane[], double VertPlane[], double jacobi_f[][4][4][4], int dx, int dy, int dz);
	void usrfun2(double point[], double fValue[], double jacobi[][3], double func[][4][4], double scanPlane[], double vertPlane[], double jacobi_f[][4][4][4], int dx, int dy, int dz);
	void SilCriticalPointOutputTraceInterval(int* Scanline_X, bool* bVisible, double* Scanline_Z, int line);
	void SilCriticalPointUVW2ScanInterval(bool bOutDomain, int Scanline_X, bool* bVisible, double Scanline_Z, double intersect[], int scanline, double* boxX, double* boxY, double* boxZ);


	void SilLaunchCUDA();
};
